package graphics.system;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.util.ArrayList;

import graphics.tools.Tools;

import network.byteConversions.ByteConverter;

import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;

import tools.Help;
import tools.Point;
public class VertexBufferObject implements Serializable {
	public enum Drawmode {
		LINES_LOOP, POLYGON, TRIANGLE_FAN, POINTS, LINES
	}
	private int vertssize;
	private int indexsize;
	private int vboid;
	private int texid;
	private int colorid;
	private int indexid;
	private Drawmode dmode;
	public VertexBufferObject(Point verts[], Drawmode mode) {
		this(mode);
		updateVerts(verts);
	}
	public VertexBufferObject(Drawmode mode) {
		this.dmode = mode;
		vertssize = -1;
		indexsize = -1;
		texid = -1;
		colorid = -1;
		vboid = GL15.glGenBuffers();
		indexid = GL15.glGenBuffers();
	}
	private void genIndexList() {
		int index[];
		switch (dmode) {
			case LINES_LOOP : {
				indexsize = vertssize;
				index = new int[indexsize];
				for (int i = 0; i < indexsize; i++) {
					index[i] = i;
				}
				GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, indexid);
				GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, Tools.arrayToIntBuffer(index), GL15.GL_DYNAMIC_DRAW);
				break;
			}
			case POLYGON : {
				indexsize = vertssize;
				index = new int[indexsize];
				for (int i = 0; i < indexsize; i++) {
					index[i] = i;
				}
				GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, indexid);
				GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, Tools.arrayToIntBuffer(index), GL15.GL_DYNAMIC_DRAW);
				break;
			}
			case TRIANGLE_FAN : {
				indexsize = vertssize + 1;
				index = new int[indexsize];
				for (int i = 0; i < indexsize; i++) {
					index[i] = i;
				}
				index[indexsize - 1] = 1;
				GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, indexid);
				GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, Tools.arrayToIntBuffer(index), GL15.GL_DYNAMIC_DRAW);
				break;
			}
			case POINTS : {
				indexsize = vertssize;
				index = new int[indexsize];
				for (int i = 0; i < indexsize; i++) {
					index[i] = i;
				}
				GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, indexid);
				GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, Tools.arrayToIntBuffer(index), GL15.GL_DYNAMIC_DRAW);
				break;
			}
			case LINES : {
				indexsize = vertssize;
				index = new int[indexsize];
				for (int i = 0; i < vertssize; i++) {
					index[i] = i;
				}
				GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, indexid);
				GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, Tools.arrayToIntBuffer(index), GL15.GL_DYNAMIC_DRAW);
				break;
			}
		}
	}
	public void updateVerts(Point verts[]) {
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboid);
		GL15.glBufferData(GL15.GL_ARRAY_BUFFER, Tools.arrayPointToFloatBuffer(verts), GL15.GL_DYNAMIC_DRAW);
		if (vertssize != verts.length) {
			vertssize = verts.length;
			genIndexList();
		}
	}
	public void draw() {
		GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboid);
		GL11.glVertexPointer(2, GL11.GL_FLOAT, 0, 0);
		if (texid != -1) {
			GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
			GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, texid);
			GL11.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0);
			GL11.glEnable(GL11.GL_TEXTURE_2D);
		}
		if (colorid != -1) {
			GL11.glEnableClientState(GL11.GL_COLOR_ARRAY);
			GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, colorid);
			GL11.glColorPointer(4, GL11.GL_FLOAT, 0, 0);
			GL11.glEnable(GL11.GL_COLOR_MATERIAL);
		}
		GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, indexid);
		switch (dmode) {
			case LINES_LOOP : {
				GL11.glDrawElements(GL11.GL_LINE_LOOP, indexsize, GL11.GL_UNSIGNED_INT, 0);
				break;
			}
			case POLYGON : {
				GL11.glDrawElements(GL11.GL_POLYGON, indexsize, GL11.GL_UNSIGNED_INT, 0);
				break;
			}
			case TRIANGLE_FAN : {
				GL11.glDrawElements(GL11.GL_TRIANGLE_FAN, indexsize, GL11.GL_UNSIGNED_INT, 0);
				break;
			}
			case POINTS : {
				GL11.glDrawElements(GL11.GL_POINTS, indexsize, GL11.GL_UNSIGNED_INT, 0);
				break;
			}
			case LINES : {
				GL11.glDrawElements(GL11.GL_LINES, indexsize, GL11.GL_UNSIGNED_INT, 0);
				break;
			}
		}
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
		GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
		GL11.glDisable(GL11.GL_TEXTURE_2D);
		GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
		GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
		GL11.glDisableClientState(GL11.GL_COLOR_ARRAY);
	}
	public void setTexCoords(Point coords[]) {
		if (coords.length != this.vertssize)
			return;
		if (texid == -1)
			texid = GL15.glGenBuffers();
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, texid);
		GL15.glBufferData(GL15.GL_ARRAY_BUFFER, Tools.arrayPointToFloatBuffer(coords), GL15.GL_DYNAMIC_DRAW);
	}
	public void setColorInfo(Color cols[]) {
		if (cols.length != this.vertssize)
			return;
		if (colorid == -1)
			colorid = GL15.glGenBuffers();
		GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, colorid);
		GL15.glBufferData(GL15.GL_ARRAY_BUFFER, Tools.arrayColorToFloatBuffer(cols), GL15.GL_DYNAMIC_DRAW);
	}
	/**
	 * draws the vbo at position
	 * 
	 * @param p
	 *            position
	 * @param angle
	 *            angle (in degrees)
	 */
	public void drawAt(Point p, float angle) {
		GL11.glPushMatrix();
		GL11.glTranslatef(p.x, p.y, 0);
		GL11.glRotatef(angle, 0, 0, 1);
		draw();
		GL11.glPopMatrix();
	}
	/**
	 * draws the vbo at position and rotates it
	 * 
	 * @param p
	 *            position
	 * @param angle
	 *            angle (in degrees)
	 * @param col
	 *            color
	 */
	public void drawAt(Point p, float angle, Color col) {
		col.set();
		GL11.glPushMatrix();
		GL11.glTranslatef(p.x, p.y, 0);
		GL11.glRotatef(angle, 0, 0, 1);
		draw();
		GL11.glPopMatrix();
	}
	public void delete() {
		GL15.glDeleteBuffers(vboid);
		GL15.glDeleteBuffers(indexid);
		removeTexCoords();
	}
	public void removeTexCoords() {
		if (texid != -1) {
			GL15.glDeleteBuffers(texid);
			texid = -1;
		}
	}
}
